package com.bbbk.util.word;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.poi.xwpf.converter.core.IXWPFConverter;
import org.apache.poi.xwpf.converter.pdf.PdfConverter;
import org.apache.poi.xwpf.converter.pdf.PdfOptions;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSON;

import cn.hutool.core.bean.BeanPath;
import cn.hutool.core.util.StrUtil;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Component
public class Word2007 {

    static String content = "{\"sellerName\":\"成都天府惠融资产管理有限公司\"," +"\"tianshu1\":\"15\","+
			"\"contractAddress\":\"1234124234\",\"sellerAccountNo\":\"1231231231\"," +
			"\"totalAmount1\":\"贰拾捌万零玖佰玖拾伍元伍角陆分\"," +
			"\"stockAddress\":\"成都达海金属加工配送有限公司（青白江区八阵大道750号）\"," +
			"\"buyerBankName\":\"中信银行股份有限公司上海长寿路支行\",\"endContactDate\":\"2021-06-02\"," +
			"\"firstRate\":\"20.0\",\"buyerContactPhone\":\"13258225171\"," +
			"\"interestStartDate\":\"2021-05-17\",\"buyerAccountNo\":\"2342142141241\"," +
			"\"arr\":[{\"deleted\":false,\"gradeName\":\"Q235B\",\"isDeleted\":false," +
			"\"price\":5000.00,\"productName\":\"热轧分卷\",\"productionBaseName\":\"攀钢钒\"," +
			"\"seq\":\"1\",\"specialDesc\":\" \",\"specification\":\"2.75*1250*C\"," +
			"\"storageName\":\"成都达海金属加工配送有限公司\",\"totalAmount\":280995.56,\"weight\":\"56\"}]," +
			"\"costRate\":\"8.00\",\"buyerTaxNo\":\"911100005858054799\"," +
			"\"buyerLegalName\":\"赵现红1\",\"referencePriceAddress\":\"四川省成都市\"," +
			"\"referencePriceCategory\":\"四川省成都市\",\"maxCycle\":\"1231\"," +
			"\"buyerName\":\"北京同仁堂药材参茸投资集团有限公司\",\"totalAmount\":\"280,995.56\"," +
			"\"sellerTaxNo\":\"91510105MA61W8XL73\",\"deliveryCycle\":90," +
			"\"sellerLegalName\":\"龚金\",\"sellerBankName\":\"成都天府惠融资产管理有限公司\"," +
			"\"demandOrderNo\":\"TFHR-GM-2021030401\"}";


    public static void main(String[] args) throws Exception {
        Word2007 word2007 = new Word2007();
        FileInputStream inputStream = new FileInputStream("C:\\Users\\tj\\Documents\\WeChat " +
                "Files\\wxid_119vbujpyx7l52\\FileStorage\\File\\2021-03\\sale_contract(1).docx");

        File file = new File("D:\\desktop\\qq3.pdf");
        //File file = new File("D:\\desktop\\qq3.docx");
        if (file.exists()) {
            file.delete();
        }
        file.createNewFile();
        FileOutputStream outputStream = new FileOutputStream(file);
        word2007.builderPdf(inputStream, outputStream, JSON.parseObject(content));
        //word2007.builderWord(inputStream, outputStream, JSON.parseObject(content));

    }

    void builderWord(InputStream inputStream, OutputStream outputStream, Object content) throws Exception {

        XWPFDocument xwpfDocument = new XWPFDocument(inputStream);

        List<XWPFTable> tables = xwpfDocument.getTables();
        List<XWPFParagraph> paragraphs = xwpfDocument.getParagraphs();

        table(tables, content);
        simp(paragraphs, content);

        xwpfDocument.write(outputStream);
        outputStream.flush();
        inputStream.close();

    }

    void builderPdf(InputStream inputStream, OutputStream outputStream, Object content) throws Exception {
        XWPFDocument xwpfDocument = new XWPFDocument(inputStream);
        List<XWPFTable> tables = xwpfDocument.getTables();
        List<XWPFParagraph> paragraphs = xwpfDocument.getParagraphs();

        table(tables, content);
        simp(paragraphs, content);
        PdfOptions pdfOptions = PdfOptions.create();

        IXWPFConverter<PdfOptions> Instance = PdfConverter.getInstance();
        Instance.convert(xwpfDocument, outputStream, pdfOptions);

    }

    void simp(List<XWPFParagraph> paragraphs, Object content) {

        log.info("paragraphs {}", paragraphs.size());
        for (int i = 0; i < paragraphs.size(); i++) {
            XWPFParagraph xwpfParagraph = paragraphs.get(i);
            List<XWPFRun> runs = xwpfParagraph.getRuns();
            StringBuilder expressionText = new StringBuilder();
            int start = -1;
            int end = -1;
            for (int j = 0; j < runs.size(); j++) {
                XWPFRun xwpfRun = runs.get(j);
                String text = xwpfRun.getText(0);
                text = text == null ? "" : text;
				if(text.contains("交货时间")){
					System.out.println(1);
				}
                if (start == -1 && text.matches(".*\\$.*")) {
                    if(text.matches(".*\\$\\{.*")){
                            start = j;
                    }else if(j+1<runs.size()){
                        String text2 = text+runs.get(j+1).getText(0);
                        if(text2.matches(".*\\$\\{.*")){
                            start = j;
                        }
                    }

                }
                if (start != -1) {
                    expressionText.append(text);
                }

                if (start != -1 && text.matches(".*\\}.*")) {
                    end = j;
                }
                if (end != -1) {
                    //expressionText.append(text);
                }
                if (start != -1 && end != -1) {

                    // 去替换
                    for (int k = start + 1; k <= end; k++) {
                        // runs.get(k).setText("", 0);
                        xwpfParagraph.removeRun(start + 1);
                    }
                    j = j - (end - start);
                    if(j!=-1)j--;
                    String newText = rep(expressionText.toString(), content, null);
                    runs.get(start).setText(newText, 0);
                    expressionText = new StringBuilder();
                    start = -1;
                    end = -1;
                }
            }
        }

    }

    static String REGEX = "\\$\\{.*?\\}";
    static String REGEX_FOR_START = "<for.*?>";
    static String REGEX_FOR_STOP = "<for.*?/>";

    void table(List<XWPFTable> tables, Object content) {
        for (XWPFTable xwpfTable : tables) {

            List<XWPFTableRow> rows = xwpfTable.getRows();
            boolean flag = false;
            ArrayList<Integer> integers = new ArrayList<>();
            String expressionForStart = null;
            for (int i = 0; i < rows.size(); i++) {
                XWPFTableRow xwpfTableRow = rows.get(i);

                List<XWPFTableCell> tableCells = xwpfTableRow.getTableCells();
                for (int i1 = 0; i1 < tableCells.size(); ) {
                    XWPFTableCell e = tableCells.get(i1);
                    String textCell = e.getText();
                    if (integers.size() == 0 && isIncludeSimp(textCell)) {
                        // 简单替换
                        replaceSimp(e, textCell, content, null);
                        i1++;
                    } else if (isIncludeForStop(textCell)) {
                        // for 循环替换
                        flag = true;
                        integers.add(i);
                        break;
                    } else if (isIncludeForStart(textCell)) {
                        // for 循环替换
                        flag = true;
                        integers.add(i);
                        expressionForStart = getExpressionForStart(textCell);
                        break;
                    } else {
                        i1++;
                    }
                }
                if (flag) {
                    xwpfTable.removeRow(i);
                    i--;
                    flag = false;
                }
                if (integers.size() == 2) {
                    Integer start = integers.get(0);
                    Integer end = integers.get(1);
                    integers.clear();
                    // 要循环表格的条数
                    int n = end - start;
                    String[] split = expressionForStart.split("\\s");
                    String item = split[0];
                    String dataName = split[split.length - 1];
                    ForDTO forDTO = new ForDTO(start, end, n, item, dataName, xwpfTable);
                    replaceFor(forDTO, content);
                }
            }
        }
    }

    @Data
    @AllArgsConstructor
    class ForDTO {
        int start;
        int end;
        int n;
        String item;
        String dataName;
        XWPFTable xwpfTable;

    }


    void replaceFor(ForDTO forDTO, Object content) {
        int start = forDTO.start;
        int end = forDTO.end;
        int n = forDTO.n;
        String item = forDTO.item;
        String dataName = forDTO.dataName;
        XWPFTable xwpfTable = forDTO.xwpfTable;
        Object itemData = resolverObject(content, dataName);

        List<XWPFTableRow> rows = xwpfTable.getRows();
        @SuppressWarnings("unchecked")
        List<Object> datas = (List<Object>) itemData;

        for (int j = 1; j < datas.size(); j++) {

            for (int i = start; i < end; i++) {

                XWPFTableRow xwpfTableRow = rows.get(i);
                copy(xwpfTable, xwpfTableRow, i + n);
            }
        }

        for (int j = 0; j < datas.size(); j++) {
            Object o = datas.get(j);
            HashMap<Object, Object> objectdata = new HashMap<>();
            objectdata.put(item, o);
            for (int i = start; i < end; i++) {
                int _thisrow = j * n + i;
                XWPFTableRow xwpfTableRow = rows.get(_thisrow);
                List<XWPFTableCell> tableCells = xwpfTableRow.getTableCells();
                for (int i1 = 0; i1 < tableCells.size(); i1++) {
                    XWPFTableCell e = tableCells.get(i1);
                    String textCell = e.getText();
                    if (StrUtil.isBlank(textCell)) {
                        List<XWPFParagraph> paragraphs = e.getParagraphs();
                        if (paragraphs != null && !paragraphs.isEmpty()) {
                            XWPFParagraph xwpfParagraph = paragraphs.get(0);
                            List<XWPFRun> runs = xwpfParagraph.getRuns();
                            if (runs != null && !runs.isEmpty()) {
                                XWPFRun run = runs.get(0);
                                textCell = run.toString();
                            }
                        }
                    }
                    if (isIncludeSimp(textCell)) {
                        // 简单替换
                        replaceSimp(e, textCell, content, objectdata);
                    }
                }
            }
        }

        // log.info("rows ={}",rows.size());
    }

    public void copy(XWPFTable table, XWPFTableRow sourceRow, int rowIndex) {
        // 在表格指定位置新增一行
        XWPFTableRow targetRow = table.insertNewTableRow(rowIndex);
        // 复制行属性
        targetRow.getCtRow().setTrPr(sourceRow.getCtRow().getTrPr());
        List<XWPFTableCell> cellList = sourceRow.getTableCells();
        if (null == cellList) {
            return;
        }
        // 复制列及其属性和内容
        XWPFTableCell targetCell = null;
        for (XWPFTableCell sourceCell : cellList) {
            targetCell = targetRow.addNewTableCell();
            // 列属性
            targetCell.getCTTc().setTcPr(sourceCell.getCTTc().getTcPr());
            // 段落属性
            if (sourceCell.getParagraphs() != null && sourceCell.getParagraphs().size() > 0) {
                targetCell.getParagraphs().get(0).getCTP().setPPr(sourceCell.getParagraphs().get(0).getCTP().getPPr());
                if (sourceCell.getParagraphs().get(0).getRuns() != null
                        && sourceCell.getParagraphs().get(0).getRuns().size() > 0) {
                    XWPFRun cellR = targetCell.getParagraphs().get(0).createRun();
                    cellR.setText(sourceCell.getText());
                    XWPFRun xwpfRun = sourceCell.getParagraphs().get(0).getRuns().get(0);
                    cellR.setBold(xwpfRun.isBold());
                    cellR.setFontFamily(xwpfRun.getFontFamily());
                } else {
                    targetCell.setText(sourceCell.getText());
                }
            } else {
                targetCell.setText(sourceCell.getText());
            }
        }
    }

    boolean isIncludeSimp(String textCell) {
        Pattern p = Pattern.compile(REGEX);
        Matcher m = p.matcher(textCell);
        return m.find();
    }

    boolean isIncludeForStart(String textCell) {
        Pattern p = Pattern.compile(REGEX_FOR_START);
        Matcher m = p.matcher(textCell);
        return m.find();
    }

    boolean isIncludeForStop(String textCell) {
        Pattern p = Pattern.compile(REGEX_FOR_STOP);
        Matcher m = p.matcher(textCell);
        return m.find();
    }

    void replaceSimp(XWPFTableCell e, String textCell, Object content, Object itemData) {
        String rep = rep(textCell, content, itemData);
        if (textCell != null && !textCell.equals(rep)) {
            List<XWPFParagraph> paragraphs = e.getParagraphs();
            int size = paragraphs.size();
            for (int j = 0; j < size - 1; j++) {
                paragraphs.remove(0);
            }
            List<XWPFRun> runs = paragraphs.get(0).getRuns();
            for (int j = 0; j < runs.size(); j++) {
                runs.get(j).setText("", 0);
            }
            runs.get(0).setText(rep);
        }
    }

    String getExpressionForStart(String textCell) {
        Pattern p = Pattern.compile(REGEX_FOR_START);
        Matcher m = p.matcher(textCell);
        while (m.find()) {
            String group = m.group();
            return m.group().substring(4, group.length() - 1).trim();
        }
        return null;
    }

    static String repFor(String textCell, Map<String, Object> content) {
        Pattern p = Pattern.compile(REGEX_FOR_START);
        Matcher m = p.matcher(textCell);
        ArrayList<String> arr = null;
        while (m.find()) {
            if (arr == null) {
                arr = new ArrayList<String>();
            }
            String b = m.group();
            arr.add(b);
            //System.out.println(b);
        }

        if (arr != null) {
            return textCell;// repAll(textCell,arr,content);
        } else {
            return textCell;
        }
    }

    static String repAllFor(String textCell, ArrayList<String> arr, Map<String, Object> content) {
        if (arr != null) {

        } else {
            return textCell;
        }
        return textCell;
    }

    static String rep(String textCell, Object content, Object itemData) {
        Pattern p = Pattern.compile(REGEX);
        Matcher m = p.matcher(textCell);
        ArrayList<String> arr = null;
        while (m.find()) {
            if (arr == null) {
                arr = new ArrayList<>();
            }
            String b = m.group();
            arr.add(b);
            //System.out.println(b);
        }

        if (arr != null) {
            return repAll(textCell, arr, content, itemData);
        } else {
            return textCell;
        }
    }

    static String repAll(String textCell, ArrayList<String> arr, Object content, Object itemData) {
        for (int i = 0; i < arr.size(); i++) {
            String s = arr.get(i);
            String substring = s.substring(2, s.length() - 1);
            String expression = substring.trim();
            //System.out.println(expression);
            String resolver = null;
            if (itemData != null) {
                resolver = resolver(itemData, expression);
            }
            if (resolver == null || "null".equals(resolver)) {
                resolver = resolver(content, expression);
            }
            textCell = textCell.replace(s, resolver);
            log.info(s + " --> " + resolver);
        }
        return textCell;
    }

    static String resolver(Object o, String expression) {
        BeanPath resolver = new BeanPath(expression);
        Object result = resolver.get(o);
        return result == null ? "null" : result.toString();
    }

    static Object resolverObject(Object o, String expression) {
        BeanPath resolver = new BeanPath(expression);
        return resolver.get(o);
    }
}
